package beanstao.util.io;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;

import beanstao.util.Encoding;
import beanstao.util.Util;

public class StreamBuffer extends InputStream
{

	private static class OutputStreamBuffer extends OutputStream
	{
		private final ArrayList<byte[]> bytes = new ArrayList<byte[]>();
		private final int width = 1024;
		private int index = 0;
		private int cursor = 0;

		@Override
		public void write(int b) throws IOException
		{
			if (this.cursor >= this.width)
			{
				this.index++;
			}
			byte[] row = this.bytes.size() > this.index ? this.bytes.get(this.index) : null;
			if (null == row)
			{
				row = new byte[this.width];
				this.bytes.add(row);
				this.cursor = 0;
			}
			row[this.cursor++] = (byte) b;
		}

		private int size()
		{
			return this.index > 0 ? this.width * (this.index - 1) + this.cursor : this.cursor;
		}

	}

	private final OutputStreamBuffer buffer = new OutputStreamBuffer();
	private int index = 0;
	private int cursor = 0;

	public OutputStream getBuffer()
	{
		return this.buffer;
	}

	public void write(int b) throws IOException
	{
		this.buffer.write(b);
	}

	@Override
	public int read() throws IOException
	{
		if (this.cursor > this.buffer.width)
		{
			this.index++;
			this.cursor = 0;
		}
		if (this.index > this.buffer.index)
		{
			return -1;
		}
		if (this.index < this.buffer.bytes.size())
		{
			byte[] cs = this.buffer.bytes.get(this.index);
			if (this.cursor < this.buffer.cursor)
			{
				return cs[this.cursor++];
			}
		}
		return -1;
	}

	@Override
	public int available() throws IOException
	{
		return this.buffer.size();
	}

	@Override
	public synchronized void reset() throws IOException
	{
		this.index = 0;
		this.cursor = 0;
	}

	@Override
	public String toString()
	{
		try
		{
			return this.toString(Encoding.defaultEncoding());
		}
		catch (IOException e)
		{
			throw Util.wrapThrow(e);
		}
	}

	public String toString(String charset) throws IOException
	{
		this.index = 0;
		this.cursor = 0;
		StringBuilder sb = new StringBuilder();
		StringOutputStream sos = new StringOutputStream(sb, charset);
		byte c;
		while ((c = (byte) this.read()) != -1)
		{
			sos.write(c);
		}
		sos.flush();
		return sb.toString();
	}

}
